/**
 * @author: David Aguilera
 */
function countCharsBefore(target, node) {
   if (target == node)
      return {offset:0, found:true};

   if (node == null)
      return {offset:0, found:false};

   var offset = 0;
   var aux = node.firstChild;

   var result = countCharsBefore(target, aux);
   while (result.found == false) {
      if (aux == null) break;
      aux = aux.nextSibling;
      var res2 = countCharsBefore(target, aux);
      result.offset += res2.offset;
      result.found = res2.found;
   }

   aux = node.firstChild;
   if (aux != null) {
      try {
         result.offset += aux.nodeValue.length;
      }
      catch (exception) {}
   }

   return result;
}

jQuery.fn.getSelection = function() {
   var obj = $(this[0])

   var text = obj.text();
   var oldHtml = obj.html();

   // We get the selection
   var sel = window.getSelection();
   var range = sel.getRangeAt(0);

   var a = range.commonAncestorContainer.parentNode;
   var offset = countCharsBefore(a, obj.get(0)).offset;

   var begin = offset + range.startOffset;
   var end = begin + range.toString().length;

   return {selection:range,
           begin:begin,
           end:end,
           length:range.toString().length,
           caret:begin,
           text:range.toString()};
}

jQuery.fn.caret = function(position) {
   var obj = $(this[0])
   if (position == undefined)
      return obj.getSelection().caret;

   var sel = window.getSelection();
   var range = sel.getRangeAt(0);
   range.setStart(obj.get(0), position);
   range.setEnd(obj.get(0), position);
}

/**
 * @param html HTML text
 * @param begin initial index
 * @param end final index
 * @param tc text (without HTML tags) counter
 * @param hc text (with HTML tags) counter
 * @param ut array of unclosed tags
 */
function checkHtmlAroundSelection(html, begin, end, tc, hc, ut) {
   var result = "";

   for (tc = begin; tc < end; ++tc) {

      // Control tags: <something>
      while (html.charAt(hc) == "<") {
         tag = "";
         while (html.charAt(hc) != ">") {
            tag += html.charAt(hc);
            ++hc;
         }
         tag += ">";

         if (tag.charAt(tag.length-2) == '/' &&
             tag.charAt(tag.length-1) == '>') {
            // Open and closed tag; nothing to do here
         }
         else if (tag == "<br>") {
            // Special tag; nothing to do here
         }
         else {
            if (tag.charAt(1) != "/")
               ut[ut.length] = tag;
            else
               ut.splice(ut.length-1, 1);
         }
         result += tag;
         ++hc;
      }

      // Control special characters: &amp;
      while (html.charAt(hc) == "&") {
         character = "";
         while (html.charAt(hc) != ";") {
            character += html.charAt(hc);
            ++hc;
         }
         character += ";";

         result += character;
         ++hc;
      }

      result += html.charAt(hc);
      ++hc;
   }

   return {result:result, tc:tc, hc:hc, ut:ut};
}

function closeTag(tag) {
   var aux = tag.substring(1);
   var i = aux.indexOf(' ');
   if (i == -1)
      aux = aux.substring(0, aux.length-1);
   else
      aux = aux.substring(0, i-1);

   return "</" + aux + ">";
}

jQuery.fn.splitSelection = function(){
   var obj = $(this[0])

   var s = obj.getSelection();
   var text = obj.text();
   var html = obj.html();

   if (s.begin == s.end) {
      if (s.begin == 0)
         return {previousHtml:"", selectionHtml: "", nextHtml:html}
      if (s.end == text.length-1)
         return {previousHtml:html, selectionHtml: "", nextHtml:""}
   }

   var prev = "";
   var next = "";

   var tc = 0;
   var hc = 0;
   var ut = new Array();
   var tag = "";

   var aux;

   aux = checkHtmlAroundSelection(html, 0, s.begin, tc, hc, ut);
   tc = aux.tc;
   hc = aux.hc;
   ut = aux.ut;
   prev = aux.result;
   // Close tags
   for (i=0; i<ut.length; ++i)
      prev += closeTag(ut[ut.length-1-i]);

   selection = "";
   if (s.begin < s.end) {
      // Open tags
      for (i=0; i<ut.length; ++i)
         selection += ut[i];
      aux = checkHtmlAroundSelection(html, s.begin, s.end, tc, hc, ut);
      tc = aux.tc;
      hc = aux.hc;
      ut = aux.ut;
      selection += aux.result;
      // Close tags
      for (i=0; i<ut.length; ++i)
         selection += closeTag(ut[ut.length-1-i]);
   }

   next = "";
   if (s.end < text.length) {
      // Open tags
      for (i=0; i<ut.length; ++i)
         next += ut[i];
      aux = checkHtmlAroundSelection(html, s.end, text.length, tc, hc, ut);
      tc = aux.tc;
      hc = aux.hc;
      ut = aux.ut;
      next += aux.result;
   }

   return {previousHtml: prev, selectionHtml:selection, nextHtml: next}
}

